const moment = require("moment");
const Service = require('egg').Service;
const bcrypt = require('bcrypt');
const _ = require('lodash');
const Parameter = require('parameter');
const parameter = new Parameter();
const Rule = require('../validate');
const shortid = require('shortid');

const chinese = /^[\u4e00-\u9fa5]{2,}$/;
let $or;

class UserService extends Service {
    // 默认不需要提供构造函数。
    constructor(ctx) {
        super(ctx);
        //如果需要在构造函数做一些处理，一定要有这句话，才能保证后面 `this.ctx`的使用。
        // 就可以直接通过 this.ctx 获取 ctx 了
        // 还可以直接通过 this.app 获取 app 了
        $or = this.app.Sequelize.Op.or;
        moment.locale('zh-cn');
    }

    async find(data) {
        //从数据库获取用户详细信息
        const orQuery = [{username: data}, {email: data}];
        if (_.isNumber(data))
            orQuery.push({id: data}, {phone: data});
        return await this.app.model.User.findOne({where: {[$or]: orQuery}});
    }

    /***
     * 验证用户数据
     * @param rule
     * @param data
     * @returns {Object}
     */
    validateData(rule, data) {
        let message;
        if (_.isEmpty(data.username))
            message = '账号为空';
        if (data.username.length < 4) {
            if (!chinese.test(data.username))
                message = '非中文字符的用户名必须大于4位字符'
        }
        if (!message) {
            const error = parameter.validate(rule, data);
            if (error) {
                switch (error[0].field) {
                    case 'username':
                        message = '账号 不符合要求';
                        break;
                    case 'email':
                        message = '邮箱 不符合要求';
                        break;
                    case 'phone':
                        message = '手机号码 不符合要求';
                        break;
                    case 'password':
                        message = '密码 不符合要求';
                        break;
                    default:
                        message = '未知错误';
                }
            }
        }

        if (message)
            return this.ctx.helper.error(message);
    }

    async checkUser(data) {
        let {id, username, email, phone} = data;
        let where = {[$or]: [{username}, {email}, {phone}]};
        if (id > 0)
            where.id = {[this.app.Sequelize.Op.ne]: id};

        let user = await this.app.model.User.unscoped().findOne({where});

        if (!!user) {
            if (user.username === username)
                throw new Error('账号已存在');
            if (user.phone === phone)
                throw new Error('手机号码已存在');
            if (user.email === email)
                throw new Error('邮箱已存在');
        }
    }

    /**
     * 注册
     * @param data
     * @param force
     * @returns {Promise<*>}
     */
    async register(data, force = false) {
        if (!force) {
            const allowRegister = await this.app.model.Config.get('allowRegister', false);
            if (!allowRegister)
                throw new Error('已经禁止新用户注册');
        }
        this.validateData(Rule.userRegister, data);

        let {username, password, email, phone} = data;

        await this.checkUser(data);

        password = await bcrypt.hash(password, 4);
        const newUser = await this.app.model.User.create({
            username,
            password,
            phone,
            email,
            level_id: this.app.userDefaultLevel
        });
        if (newUser.id === 2)
            newUser.update({level_id: 2});

        this.app.model.UserMessage.create({message_id: 1, user_id: newUser.id});

        return newUser;
    }

    /**
     * 登录
     * @param data
     * @returns {Promise<*>}
     */
    async login(data) {
        this.validateData(Rule.userLogin, data);

        const {username, password} = data;

        const orQuery = [{username}, {email: username}, {phone: username}];
        let user = await this.app.model.User.unscoped().findOne({
            where: {id: {[this.app.Sequelize.Op.gt]: 1}, [$or]: orQuery},
        });
        if (!user)
            throw new Error('不存在的用户');
        if (user.disable) {
            let disable = new Date(user.disable).getTime();
            const now = Date.now();
            if (disable > now) {
                disable = moment(disable).calendar();
                throw new Error(`${username} 被禁止登录，${disable} 后解禁`);
            }
        }

        const same = await bcrypt.compare(password, user.password);
        if (!same)
            throw new Error('密码错误');

        user.update({last_sign_in_at: new Date()});

        user = _.pick(user.toJSON(), ['id']);
        user.random = shortid.generate();
        // console.log('登录', user);
        return user;
    }

    /**
     * 重置账号密码
     * @param userId
     * @param password
     * @returns {Promise<boolean>}
     */
    async resetPassword({userId, password}) {
        const user = await this.app.model.User.findByPk(userId);
        if (!user)
            return false;
        password = await bcrypt.hash(password, 4);
        await user.update({password});
        return true;
    }
}

module.exports = UserService;